package dhy.com.handler;


import dhy.com.container.RpcContainerImpl;
import dhy.com.exception.RpcContainerException;
import dhy.com.message.RpcRequestMessage;
import dhy.com.message.RpcResponseMessage;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;


/**
 * <p>
 *     请求消息处理器,只处理RpcRequestMessage消息类型
 * </p>
 * @author zdh
 */
@Slf4j
@ChannelHandler.Sharable
public class RpcRequestMessageHandler extends SimpleChannelInboundHandler<RpcRequestMessage> {


    /**
      * 读取到客户方发来的消息,取出里面的消息数据,然后调用执行对应的方法,返回方法的返回结果
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequestMessage message) {
        log.debug("接收到客户方发送来的消息为: {}",message);
        //创建响应消息
        RpcResponseMessage response = new RpcResponseMessage();
        //设置响应消息的序列号为请求消息的序列化,保证消息接收的一致性
        response.setSequenceId(message.getSequenceId());
        try {
            //正常获取结果,写入正常的方法返回结果
            Object invoke = handlerRequestMessage(message);
            response.setReturnValue(invoke);
        } catch (Exception e) {
            e.printStackTrace();
            //抛出异常,写出异常消息
            String msg = e.getCause().getMessage();
            Exception exception = new Exception("远程调用出错:" + msg);
            System.out.println(exception);
            response.setExceptionValue(exception);
        }
        //写出响应消息
        ctx.writeAndFlush(response);
    }

    public Object handlerRequestMessage(RpcRequestMessage message) throws RpcContainerException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //从容器中找到对应的service标注的接口,反射调用目标方法
        Class server = RpcContainerImpl.getInstanceFromServer(message.getInterfaceName());
        if(server==null)
        {
            throw new RpcContainerException("未能在服务端找到对应的实例对象");
        }
        AtomicReference<Object> res=new AtomicReference<>();
        //找到对应方法,执行,返回结果
        for (Method method : server.getMethods()) {
            if(method.getName().equals(message.getMethodName()))
            {
                res.set(method.invoke(server.newInstance(), message.getParameterValue()));
            }
        }
        return res.get();
    }
}
